module run_manager

    implicit none

    private

    public run_manager_register_end
    public run_manager_end_run

    type subroutine_handle
        character(20) :: module_name
        character(20) :: subroutine_name
        procedure(), nopass, pointer :: handle
        type(subroutine_handle), pointer :: next
    end type subroutine_handle

    integer :: num_end_handle
    type(subroutine_handle), pointer :: end_entry

contains

    subroutine run_manager_register_end(module_name, &
        subroutine_name, handle)
        character(*), intent(in) :: module_name
        character(*), intent(in) :: subroutine_name
        procedure(), intent(in), pointer :: handle

        type(subroutine_handle), pointer :: end_ptr
        integer :: i

        if(associated(end_entry) == .false.) then
            num_end_handle = 1
            allocate(end_entry)
            nullify(end_entry%next)
        else
            num_end_handle = num_end_handle+1
        end if

        end_ptr => end_entry
        do i = 2, num_end_handle
            allocate(end_ptr%next)
            end_ptr => end_ptr%next
            nullify(end_ptr%next)
        end do

        end_ptr%module_name = module_name
        end_ptr%subroutine_name = subroutine_name
        end_ptr%handle => handle

        return
    end subroutine run_manager_register_end

    subroutine run_manager_end_run
        type(subroutine_handle), pointer :: end_ptr
        integer :: i

        end_ptr => end_entry
        do i = 1, num_end_handle
            write(*, "('ending ')", advance="no")
            write(*, "(a, '::')", advance="no") &
                trim(end_ptr%module_name)
            write(*, "(a, ' ... ')", advance="no") &
                trim(end_ptr%subroutine_name)
            call end_ptr%handle
            write(*, "('done')")
            end_ptr => end_ptr%next
        end do

        stop

    end subroutine run_manager_end_run

end module run_manager
